package com.jiangli.aspect;

import com.jiangli.annotation.RateLimit;
import com.jiangli.context.BaseContext;
import com.jiangli.utils.SlidingWindowRateLimiter;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class RateLimitAspect {

    @Autowired
    private SlidingWindowRateLimiter rateLimiter;

    @Autowired
    private HttpServletRequest request;

    // 定义切点：拦截所有标注了@RateLimit的方法
    @Pointcut("@annotation(com.jiangli.annotation.RateLimit)")
    public void rateLimitPointcut() {}

    // 使用@Around环绕通知，更安全地获取方法信息（兼容JDK 17）
    @Around("rateLimitPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取方法上的@RateLimit注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        RateLimit rateLimit = signature.getMethod().getAnnotation(RateLimit.class);
        if (rateLimit == null) {
            // 没有注解时直接执行方法
            return joinPoint.proceed();
        }

        // 2. 获取客户端标识（IP或用户ID）
        String clientKey = getClientIdentifier();

        // 3. 获取当前请求的接口路径
        String apiPath = request.getRequestURI();

        // 4. 调用限流工具类检查
        boolean allowed = rateLimiter.allowRequest(
                clientKey,
                apiPath,
                rateLimit.windowSize(),
                rateLimit.maxRequests()
        );

        // 5. 限流判断
        if (!allowed) {
            throw new RateLimitException(rateLimit.message());
        }

        // 6. 通过限流，执行原方法
        return joinPoint.proceed();
    }

    /**
     * 获取客户端标识（优先用户ID，其次IP）
     */
    private String getClientIdentifier() {
        // 从请求头获取登录用户ID（根据实际认证方式调整）
        String userId =
                String.valueOf(BaseContext.getCurrentId());
        if (userId != null && !userId.isEmpty()) {
            return userId;
        }
        // 未登录用户使用IP
        return getClientIp();
    }

    /**
     * 获取客户端真实IP（处理代理场景）
     */
    private String getClientIp() {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 处理多IP情况（多级代理）
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }

    /**
     * 限流异常类
     */
    public static class RateLimitException extends RuntimeException {
        public RateLimitException(String message) {
            super(message);
        }
    }
}
